// 12.2.1 类型参数
// 类型参数是C++模板中最常见的参数形式，它允许我们创建能够处理不同数据类型的通用代码。以下是关于类型参数的详细解释：

// 基本语法
// 类型参数可以使用两种关键字声明：typename 或 class，这两者在功能上完全等价：

// 使用typename关键字
template <typename T>
class Container1
{
    T element;
};

// 使用class关键字
template <class T>
class Container2
{
    T element;
};

// typename 与 class 的选择
// 虽然这两个关键字在功能上相同，但有一些使用惯例：
// 1.现代C++倾向于使用typename：它更清晰地表明参数是一个类型，而不仅仅是类
// 2.历史原因：class是C++早期版本中唯一可用的选项，typename是在C++98中引入的
// 3.一致性：在一个项目中最好统一使用一种风格

// 类型参数的作用域
// 类型参数的作用域从声明点开始，到模板定义结束：
template <typename T> // T的作用域开始
class Stack
{
    // T在这里可用

    template <typename U> // U的作用域开始
    void convert(U value)
    {
        // T和U在这里都可用
    } // U的作用域结束

}; // T的作用域结束

// 类型参数的使用
// 类型参数可以在模板内部用于多种目的：
// 1.变量类型：
template <typename T>
class Container
{
    T value; // T作为变量类型
};

// 2.返回类型和参数类型：
template <typename T>
T function(T param)
{ // T作为返回类型和参数类型
    return param;
}

// 3.嵌套类型：
template <typename T>
class Outer
{
    class Inner
    {
        T value; // 在嵌套类中使用T
    };
};

// 4.基类：
template <typename T>
class Derived : public T
{ // T作为基类
  // ...
};

// 默认类型参数
// 类型参数可以有默认值，这在用户不指定类型时使用：
template <typename T = int>
class DefaultInt
{
    T value;
};

DefaultInt<> obj; // 使用默认类型int

// 类型参数的约束（C++20）
// 在C++20中，可以使用概念（Concepts）对类型参数添加约束：
template <typename T>
concept Numeric = std::is_arithmetic_v<T>;

template <Numeric T> // T必须满足Numeric概念
class NumericContainer
{
    T value;
};

// 类型参数的命名约定
// 虽然没有强制规定，但有一些常见的命名约定：
// 1.单个大写字母：T, U, V 等用于一般类型
// 2.有意义的名称：ElementType, KeyType, ValueType 等用于表明用途
// 3.特定前缀：T_ 前缀表示类型参数

// 类型参数的限制
// 类型参数有一些限制：
// 1.不能用于模板的非类型参数位置
// 2.在C++17之前，不能直接用于模板模板参数
// 3.在某些上下文中，需要使用typename关键字来消除歧义
